using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Net.Mail;
using System.Collections.Specialized;
using System.Diagnostics;

namespace SendHTML
{
    class HtmlFile
    {
        private string _filepath;
        private string _rawhtml;

        public HtmlFile(string filename)
        {
            this.filename = filename;
        }

        public string filename
        {
            get { return _filepath; }
            set {
                _filepath = value;
                ParseBodyFromFile();
            }
        }
	
        private void ParseBodyFromFile()
        {
            StreamReader sr = File.OpenText(_filepath);
            _rawhtml = sr.ReadToEnd();
            sr.Close();
        }

        public string Directory
        {
            get
            {
                return _filepath.Substring(0, _filepath.LastIndexOf("\\")+1);
            }
        }

        public AlternateView ConvertToMIME()
        {
            string mimehtml;
            string path = this.Directory;

            //strip iframe and script tags
            mimehtml = StripHtmlTag("script", _rawhtml);
            mimehtml = StripHtmlTag("iframe", mimehtml);

            //get external files
            NameValueCollection exfiles = ExternalFiles(mimehtml);

            //convert file names to content identifies
            mimehtml = ConvertReferencesToCID(mimehtml, exfiles);

            //then we create the HTML part
            Debug.WriteLine(mimehtml);
            AlternateView htmlView = AlternateView.CreateAlternateViewFromString(mimehtml, null, "text/html");

            for (int i = 0; i < exfiles.Count; i++)
            {
                //create the LinkedResource (embedded video)
                LinkedResource linkfile = new LinkedResource(path + exfiles[i], GetContentType(exfiles[i]));
                linkfile.ContentType.Name = exfiles[i];
                linkfile.ContentId = DeriveContentId(exfiles[i]);

                //add the LinkedResource to the appropriate view
                htmlView.LinkedResources.Add(linkfile);
                Debug.WriteLine("Adding " + path + exfiles[i] + " as " + linkfile.ContentId);
            }
            return htmlView;
        }

        public AlternateView SimpleConvert()
        {
            //try alternative conversion with CID's

            //get external files
            NameValueCollection exfiles = ExternalFiles(_rawhtml);

            //then we create the HTML part
            AlternateView htmlView = AlternateView.CreateAlternateViewFromString(_rawhtml, null, "text/html");

            string path = this.Directory;
            for (int i = 0; i < exfiles.Count; i++)
            {
                //create the LinkedResource (embedded video)
                LinkedResource linkfile = new LinkedResource(path + exfiles[i], GetContentType(exfiles[i]));
                linkfile.ContentId = exfiles[i];

                //add the LinkedResource to the appropriate view
                htmlView.LinkedResources.Add(linkfile);
                Debug.WriteLine("Adding " + path + exfiles[i] + " as " + linkfile.ContentId);
            }
            return htmlView;
        }

        private string StripHtmlTag(string tagName, string html)
        {
            Regex reg = new Regex(String.Format(@"<{0}[^>]*?>[\w|\t|\r|\W]*?</{0}>", tagName), RegexOptions.Multiline | RegexOptions.IgnoreCase);
            return reg.Replace(html, "");
        }

        private NameValueCollection ExternalFiles(string html)
        {
            NameValueCollection externalFileCollection = new NameValueCollection();
            Regex r;


            Debug.WriteLine("Resolving external file references:");

            // src='filename.ext' ; background="filename.ext" ; dynsrc= ; href=
            // note that we have to test 3 times to catch all quote styles: '', "", and none
            r = new Regex("(\\ssrc|\\sbackground|\\shref|\\sdynsrc)\\s*=\\s*((?<Key>'(?<Value>[^']+)')|(?<Key>\"(?<Value>[^\"]+)\")|(?<Key>(?<Value>[^ \\n\\r\\f]+)))", RegexOptions.IgnoreCase | RegexOptions.Multiline);
            AddMatchesToCollection(html, r, ref externalFileCollection);

            // @import "style.css" or @import url(style.css)
            r = new Regex("(@import\\s|\\S+-image:|background:)\\s*?(url)*\\s*?(?<Key>[\"'(]{1,2}(?<Value>[^\"')]+)[\"')]{1,2})", RegexOptions.IgnoreCase | RegexOptions.Multiline);
            AddMatchesToCollection(html, r, ref externalFileCollection);

            // <link rel=stylesheet href="style.css">
            r = new Regex("<link[^>]+?href\\s*=\\s*(?<Key>('|\")*(?<Value>[^'\">]+)('|\")*)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
            AddMatchesToCollection(html, r, ref externalFileCollection);

            Debug.WriteLine("Total Files = " + externalFileCollection.Count);

            return externalFileCollection;
        }

        private void AddMatchesToCollection(string s, Regex r, ref NameValueCollection nvc)
        {
            string key;
            string value;
            bool headerDisplayed = false;
            Regex urlRegex = new Regex("^https*://\\w+", RegexOptions.IgnoreCase);
            foreach (Match m in r.Matches(s))
            {
                if (!(headerDisplayed))
                {
                    Debug.WriteLine("Matches added from regex:");
                    Debug.WriteLine("\"" + r.ToString() + "\"");
                    headerDisplayed = true;
                }
                key = m.Groups["Key"].ToString();
                value = m.Groups["Value"].ToString();
                if (nvc[key] == null)
                {
                    Debug.WriteLine(" Match: " + m.ToString());
                    Debug.WriteLine(" Key: " + key);
                    Debug.WriteLine(" Value: " + value);
                    if ((urlRegex.IsMatch(value)))
                    {
                        Debug.WriteLine("Match discarded; http:// Url found", "Error");
                    }
                    else
                    {
                        nvc.Add(key, value);
                    }
                }
            }
        }

        public string ConvertReferencesToCID(string html, NameValueCollection exfiles)
        {
            if (exfiles.Count == 0)
            {
                return html;
            }

            foreach (string delimitedFileName in exfiles.AllKeys)
            {
                string origFileName = exfiles[delimitedFileName];
                string newFileName = "cid:" + DeriveContentId(origFileName);
                string replacementFileName = Regex.Replace(delimitedFileName, "^(?<StartDelim>\"|'|\\()*(?<Value>[^'\")]*)(?<EndDelim>\"|'|\\))*$", "${StartDelim}" + newFileName + "${EndDelim}");
                html = html.Replace(delimitedFileName, replacementFileName);
            }
            return html;
        }

        private string DeriveContentId(string filename)
        {
            StringBuilder cid = new StringBuilder(filename);
            cid.Replace('\\', '-');
            cid.Replace('/', '-');
            return cid.ToString();
        }

        private string GetContentType(string filename)
        {
            int lastdot = filename.LastIndexOf(".");
            string fileext = filename.Substring(lastdot + 1, 3).ToLower();
            
            switch (fileext)
        	{
                case "jpg": return "image/jpeg";
                case "gif": return "image/gif";
                case "png": return "image/x-png";
                case "bmp": return "image/bmp";
                case "css": return "text/css";
                case "mpg": return "video/mpeg";
                case "avi": return "video/x-msvideo";
                case "asf": return "video/x-ms-asf"; 
                case "asx": return "video/x-ms-asx";
                case "wmv": return "video/x-ms-wmv";
                case "wvx": return "video/x-ms-wvx";
                case "wmx": return "video/x-ms-wmx";

	        default:
                Debug.WriteLine("Unknown content type for " + fileext);
                return null;
            }
        }
    }
}
